﻿#include <QDebug>
#include <QMutexLocker>

#include "PlayBackControl.h"

//!时间间隔，即精度：默认设置为100毫秒
#define TIME_SPAN 100000

PlayBackControl::PlayBackControl(const PlayBackTimerType mode, QObject *parent) : QObject(parent)
{
    m_TimerType = mode;
    isRuning = false;
    m_StartDate = QDate(2000,1,1);
    m_PlayMode = Forward;
    m_PlaySpeed = 1;

    m_pQtTimer = new GY_QtTimer();
    m_pCPUTimer = new GY_CPUCounterTimer();

    //!接收计时器信号
    connect(m_pQtTimer,&GY_QtTimer::timeOutSiganl,this,&PlayBackControl::timeOutEvent);
    connect(m_pCPUTimer,&GY_CPUCounterTimer::timeOutSiganl,this,&PlayBackControl::timeOutEvent);
}

PlayBackControl::~PlayBackControl()
{
    stopPlaying();
    delete m_pQtTimer;
    delete m_pCPUTimer;
}

/**
 * @brief PlayBackControl::setTimerMode 设置计时器类型
 * @param mode 类型
 */
void PlayBackControl::setTimerMode(const PlayBackControl::PlayBackTimerType mode)
{
    //运行时不能进行计时器类型设置
    if(isRuning){
        return;
    }
    m_TimerType = mode;
}

/**
 * @brief PlayBackControl::setCurrentDateTime 设置当前日期、时间
 * @param time 时间
 * @param date 日期
 */
void PlayBackControl::setCurrentDateTime(const quint64 &time, const QDate &date)
{
    if(m_TimerType == QtTimer){
        m_pQtTimer->setCurrentTime(time);
        m_pQtTimer->setCurrentDate(date);
    }else{
        m_pCPUTimer->setCurrentTime(time);
        m_pCPUTimer->setCurrentDate(date);
    }

    QMutexLocker locker(&m_Mutex);
    auto pair = findPlayBackDatas(time, date);
    auto begin = pair.first, end = pair.second;

    if(begin < end)
    {
        auto data = *(end - 1);
        emit sendPlayBackDataSignal(date, time, data.date, data.time, data.msgId, data.data);
        m_PlayBackDatas.erase(pair.first, pair.second);
    }
}
/**
 * @brief currentDateTime 获取当前日期事件
 * @return  返回当前日期时间
 */
QDateTime PlayBackControl::currentDateTime() const
{
    auto date = QtTimer == m_TimerType ? m_pQtTimer->getCurrentDate() : m_pCPUTimer->getCurrentDate();
    auto time = QtTimer == m_TimerType ? m_pQtTimer->getCurrentTime() : m_pCPUTimer->getCurrentTime();
    return QDateTime(date, QTime(0, 0).addMSecs(time * 0.001));
}
/**
 * @brief currentDate 获取当前日期
 * @return 当前日期
 */
QDate PlayBackControl::currentDate() const
{
    return QtTimer == m_TimerType ? m_pQtTimer->getCurrentDate() : m_pCPUTimer->getCurrentDate();
}
/**
 * @brief currentTime 获取当前时间
 * @return 当前时间(微妙数)
 */
quint64 PlayBackControl::currentTime() const
{
   return QtTimer == m_TimerType ? m_pQtTimer->getCurrentTime() : m_pCPUTimer->getCurrentTime();
}
/**
 * @brief setPlayMode 设置播放模式
 * @param mode 待设置的模式
 */
void PlayBackControl::setPlayMode(PlayBackControl::PlayMode mode)
{
    if(m_PlayMode != mode)
    {
        m_PlayMode = mode;
        m_PlayBackDatas.clear();

        if(m_PlayMode == Forward)
            emit addForwardDataQueSignal();
        else if(m_PlayMode == BackOff)
            emit addBackOffDataQueSignal();

        m_PlaySpeed = 1;
        auto speed = m_PlaySpeed * m_PlayMode;
        m_pQtTimer->setTimerSpeed(speed);
        m_pCPUTimer->setTimerSpeed(speed);
    }
}
/**
 * @brief playMode 获取播放模式
 * @return 播放模式枚举(前进/后退)
 */
PlayBackControl::PlayMode PlayBackControl::playMode() const
{
    return m_PlayMode;
}
/**
 * @brief setPlaySpeed 设置播放倍速
 * @param speed 待设置的倍速
 */
void PlayBackControl::setPlaySpeed(double speed)
{
    if(m_PlaySpeed != speed)
    {
        m_PlaySpeed = speed;
        auto speed = m_PlaySpeed * m_PlayMode;
        m_pQtTimer->setTimerSpeed(speed);
        m_pCPUTimer->setTimerSpeed(speed);
    }
}
/**
 * @brief playSpeed 获取播放速度
 * @return 播放倍速
 */
double PlayBackControl::playSpeed() const
{
    return m_PlaySpeed;
}
/**
 * @brief clear 清除回放数据
 */
void PlayBackControl::clear()
{
    m_PlayBackDatas.clear();
}
/**
 * @brief startPlayBack 开始
 */
void PlayBackControl::startPlayBack()
{
    if(isRuning)
    {
        return;
    }
    isRuning = true;

    if(m_TimerType == QtTimer){
        m_pQtTimer->startTimer(TIME_SPAN); //时间间隔
    }else{
        m_pCPUTimer->startTimer();
    }
}

/**
 * @brief stopPlaying 停止
 */
void PlayBackControl::stopPlaying()
{
    setStartEndDateTime(m_StartTime, m_EndTime, m_StartDate, m_EndDate);
    m_PlayBackDatas.clear();
    if(!isRuning)
    {
        return;
    }
    isRuning = false;
    if(m_TimerType == QtTimer){
        m_pQtTimer->stopTimer();
        m_pQtTimer->setCurrentTime(m_StartTime);
        m_pQtTimer->setCurrentDate(m_StartDate);
    }else{
        m_pCPUTimer->stopTimer();
        m_pCPUTimer->setCurrentTime(m_StartTime);
        m_pCPUTimer->setCurrentDate(m_StartDate);
    }
    clear();
}

/**
 * @brief pausePlaying 暂停
 */
void PlayBackControl::pausePlaying()
{
    if(!isRuning)
    {
        return;
    }
    isRuning = false;

    if(m_TimerType == QtTimer){
        m_pQtTimer->stopTimer();
    }else{
        m_pCPUTimer->stopTimer();
    }
}
/**
 * @brief startDate 开始日期
 * @return 返回开始日期
 */
QDate PlayBackControl::startDate() const
{
    return  m_StartDate;
}
/**
 * @brief endDate 结束日期
 * @return 返回结束日期
 */
QDate PlayBackControl::endDate() const
{
    return  m_EndDate;
}
/**
 * @brief startTime 开始时间
 * @return 返回开始时间
 */
qint64 PlayBackControl::startTime() const
{
    return  m_StartTime;
}
/**
 * @brief endTime 结束时间
 * @return  返回结束时间
 */
qint64 PlayBackControl::endTime() const
{
     return  m_EndTime;
}

QPair<QList<PlayBackControl::PlayBackDataInfo>::iterator, QList<PlayBackControl::PlayBackDataInfo>::iterator> PlayBackControl::findPlayBackDatas(qint64 time, const QDate& date)
{
    auto begin = m_PlayBackDatas.begin(), end = begin - 1;
    if(false == m_PlayBackDatas.isEmpty())
    {
        for(auto itr = m_PlayBackDatas.begin(); itr != m_PlayBackDatas.end(); ++itr)
        {
            auto data = *itr;
            if((Forward == m_PlayMode && (data.date < date || (data.date == date && data.time <= time)))
            || (BackOff == m_PlayMode && (data.date > date || (data.date == date && data.time >= time))))
                end = itr + 1;
            else break;
        }
    }
    return qMakePair(begin, end);
}

/**
 * @brief PlayBackControl::addPlayBackData 添加回放数据
 * @param date 日期
 * @param time 时间：us
 * @param msgId 消息id
 * @param data 数据
 */
void PlayBackControl::addPlayBackData(const QDate& date, const quint64 &time, const QVariant &msgId, const QVariant& data)
{
    //将消息加入队列
    PlayBackDataInfo info;
    info.date = date;
    info.time = time;
    info.msgId = msgId;
    info.data = data;
    QMutexLocker locker(&m_Mutex);
    m_PlayBackDatas.enqueue(info);
}

/**
 * @brief PlayBackControl::timeOutEvent 定时器事件
 * @param currentDate 日期
 * @param currentTime 时间
 */
void PlayBackControl::timeOutEvent(const QDate &currentDate, const qint64 &currentTime)
{
    if((Forward == m_PlayMode && (currentDate > m_EndDate || (currentDate == m_EndDate && currentTime >= m_EndTime)))
    || (BackOff == m_PlayMode && (currentDate < m_StartDate || (currentDate == m_StartDate && currentTime <= m_StartTime))))
    {
        if(m_TimerType == QtTimer)
            m_pQtTimer->stopTimer();
        else m_pCPUTimer->stopTimer();
        isRuning = false;
    }

    //取出队列里的数据
    QMutexLocker locker(&m_Mutex);
    auto pair = findPlayBackDatas(currentTime, currentDate);
    auto begin = pair.first, end = pair.second;
    if(begin < end)
    {
        while(begin < end)
        {
            auto data = *begin++;
            emit sendPlayBackDataSignal(currentDate, currentTime, data.date, data.time, data.msgId, data.data);
        }
        m_PlayBackDatas.erase(pair.first, pair.second);
    }
    else sendPlayBackDataSignal(currentDate, currentTime);
}

/**
 * @brief setStartEndDateTime 设置开始、结束的日期和时间
 * @param startTime 开始时间
 * @param endTime 结束时间
 * @param startDate 开始日期：默认2000-1-1
 * @param endDate 结束日期：默认2000-1-1
 */
void PlayBackControl::setStartEndDateTime(const quint64 &startTime, const quint64 &endTime, const QDate &startDate, const QDate &endDate)
{
    if(isRuning || endTime<startTime || endDate<startDate){
        return;
    }

    m_StartTime = startTime;
    m_StartDate = startDate;
    m_EndTime = endTime;
    m_EndDate = endDate;

    if(m_TimerType == QtTimer){
        m_pQtTimer->setCurrentDate(startDate);
        m_pQtTimer->setCurrentTime(startTime);
    }else{
        m_pCPUTimer->setCurrentDate(startDate);
        m_pCPUTimer->setCurrentTime(startTime);
    }
}









